/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp.manager;


import cz.pecinovsky.english.lootp.manager.CanvasManager_Envelope.CanvasManager;



////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++

import cz.pecinovsky.english.lootp.utility.Area;
import cz.pecinovsky.english.lootp.utility.Position;
import cz.pecinovsky.english.lootp.utility.Size;

import java.awt.Image;
import java.awt.Toolkit;
import java.net.MalformedURLException;
import java.net.URL;
import java.awt.geom.AffineTransform;

//import odkladky.TestObrázek;

//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */


////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++


/*******************************************************************************
 * Instance třídy {@code Picture} představují obrázky,
 * které je možné načíst ze souborů nebo vytvořit z oblasti plátna.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */

public class Picture implements IChangeable//, IKopírovatelný
{
//== CONSTANT CLASS ATTRIBUTES =================================================

    /** Instance třídy {@link CanvasManager} spravující plátno,
     *  na které se všechny tvary kreslí. */
    protected static final CanvasManager CM = CanvasManager.getInstance();



//== VARIABLE CLASS ATTRIBUTES =================================================

    /** Celkový countCreated vytvořených instancí. */
    private static int countCreated = 0;



//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ========
//== CONSTANT INSTANCE ATTRIBUTES ==============================================

    /** Rodné číslo instance (její identifikátor v rámci třídy) je odvozeno
     *  z getIndexOf jejího vytvoření. */
    protected final int ID = ++countCreated;

    /** Obalený obrázek. */
    private final Image image;

    /** Rozměry originálního obrázku. */
    private final int máŠířka, máVýška;



//== VARIABLE INSTANCE ATTRIBUTES ==============================================

    /** Název instance sestávající implicitně z jednoduchého názvu třídy
     *  následovaným potržítkem a {@code ID} instance */
    private String name = "Obrázek_" + ID;

    /** Bodová x-ová souřadnice instance. */
    private int xPos;

    /** Bodová y-ová souřadnice instance. */
    private int yPos;

    /** Šířka v bodech. */
    protected int šířka;

    /** Výška v bodech. */
    protected int výška;

    /** Afinní transformace zodpovědná za změny velikosti obrázku. */
    AffineTransform aft;



//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Přečte ze zadaného souboru obrázek, který bude kreslit
     * na zadaných souřadnicích; pomocí úvodních hvězdiček
     * je možno zadat, zda se daný soubor bude hledat ve složce
     * balíčku třídy volající metody (pak musí jméno předcházet *&#47;),
     * nebo ve složce kořenovéhío balíčku (pak musí předcházet **&#47;);
     *
     * @param x      Vodorovná souřadnice levého horního rohu obrázku
     * @param y      Svislá souřadnice levého horního rohu obrázku
     * @param soubor Název souboru, v němž je obrázek uložen
     */
    public Picture(int x, int y, String soubor)
    {
        this(x, y, soubor, null);
    }


    /***************************************************************************
     * Vytvoří nový obrázek ze zadaného obrázku - instance třídy
     * <code>java.awt.Image</code> a umístí jej do počátku.
     *
     * @param x      Vodorovná souřadnice levého horního rohu obrázku
     * @param y      Svislá souřadnice levého horního rohu obrázku
     * @param obrázek Instance třídy <code>java.awt.Image</code>,
     *                která bude základem obrázku.
     */
    public Picture(int x, int y, Image obrázek)
    {
        this(x, y, null, obrázek);
    }


    /***************************************************************************
     * Přečte ze zadaného souboru obrázek, který bude kreslit
     * na zadaných souřadnicích; pomocí úvodních hvězdiček
     * je možno zadat, zda se daný soubor bude hledat ve složce
     * balíčku třídy volající metody (pak musí jméno předcházet *&#47;),
     * nebo ve složce kořenovéhío balíčku (pak musí předcházet **&#47;);
     *
     * @param x      Vodorovná souřadnice levého horního rohu obrázku
     * @param y      Svislá souřadnice levého horního rohu obrázku
     * @param soubor Název souboru, v němž je obrázek uložen
     * @param obrázek Instance třídy <code>java.awt.Image</code>,
     *                která bude základem obrázku.
     */
    private Picture(int x, int y, String soubor, Image obrázek)
    {
        //Test platnosti parametru
        if ((x<0) || (y<0)) {
            throw new IllegalArgumentException(
                "\nParametry nemají povolené hodnoty: x=" + x + ", y=" + y);
        }
        //Parametry akceptovány --> můžeme tvořit
        this.xPos  = x;
        this.yPos  = y;
        if (obrázek != null) {
            this.image = obrázek;
        } else {
            URL url;
            if (soubor.charAt(0) == '*') {
                if (soubor.charAt(1) == '*') {
                    String jméno = soubor.substring(3);
                    url = getClass().getClassLoader().getResource(jméno);
                } else {
                    Throwable t = new Throwable();
                    StackTraceElement ste = t.getStackTrace()[1];
                    String clsn = ste.getClassName();
                    Class<?> clss;
                    try{ clss = Class.forName(clsn);
                    } catch(ClassNotFoundException exc) {
                        throw new RuntimeException(
                            "\nNěco se podělalo - nenašel existující třídu " +
                            clsn, exc);
                    }
                    String jméno = soubor.substring(2);
                    url = clss.getResource(jméno);
                }
            }else {
                try {
                    url = new URL(soubor);
                } catch(MalformedURLException exc) {
                    throw new RuntimeException(
                            "\nNepodařilo se načíst obrázek v souboru " + soubor, exc);
                }
            }
            this.image = Toolkit.getDefaultToolkit().getImage(url);
        }
        máŠířka = obrázek.getWidth (Painter.IMG_OBSERVER);
        máVýška = obrázek.getHeight(Painter.IMG_OBSERVER);
        this.šířka = máŠířka;
        this.výška = máVýška;
    }



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================

    /***************************************************************************
     * Vrátí název instance - implicitně name třídy následovaný ID instance.
     *
     * @return  Řetězec s názvem instance
     */
     public String getName()
     {
        return name;
     }


    /***************************************************************************
     * Nastaví nový name instance.
     *
     * @param name  Řetězec s novým názvem instance
     */
    public void setName(String name)
    {
        this.name = name;
    }


    /***************************************************************************
     * Vrátí x-ovou souřadnici pozice instance.
     *
     * @return  x-ová souřadnice
     */
    public int getX()
    {
        return xPos;
    }


    /***************************************************************************
     * Vrátí y-ovou souřadnici pozice instance.
     *
     * @return  y-ová souřadnice
     */
    public int getY()
    {
        return yPos;
    }


    /***************************************************************************
     * Vrátí instanci třídy Position s pozicí instance.
     *
     * @return   Position s pozicí instance
     */
    @Override
    public Position getPosition()
    {
        return new Position(getX(), getY());
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová souřadnice instance
     * @param y   Nová y-ová souřadnice instance
     */
    @Override
    public void setPosition(int x, int y)
    {
        if (aft != null) {
            aft.translate((x-getX()) / aft.getScaleX(),
                           (y-getY()) / aft.getScaleY());
        }
        xPos = x;
        yPos = y;
        CM.redraw();
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param pozice   Nová pozice instance
     */
    @Override
    public void setPosition(Position pozice)
    {
        setPosition(pozice.x, pozice.y);
    }


    /***************************************************************************
     * Vrátí šířku instance.
     *
     * @return  width instance v bodech
     */
     public int getWidth()
     {
         return šířka;
     }


    /***************************************************************************
     * Vrátí výšku instance.
     *
     * @return  height instance v bodech
     */
     public int getHeight()
     {
         return výška;
     }


    /***************************************************************************
     * Vrátí instanci třídy Size s rozměry instance.
     *
     * @return   Size s rozměry instance.
     */
    @Override
    public Size getSize()
    {
        return new Size(getWidth(), getHeight());
    }


    /***************************************************************************
     * Nastaví nový "čtvercový" rozměr instance -
     * na zadaný rozměr se nastaví height i width.
     *
     * @param rozměr  Nově nastavovaný rozměr v obou směrech; rozměr>0
     */
    public void setSize(int rozměr)
    {
        setSize(rozměr, rozměr);
    }


    /***************************************************************************
     * Nastaví nové rozměry instance.
     *
     * @param rozměr    Nově nastavovaný rozměr.
     */
    @Override
    public void setSize(Size rozměr)
    {
        setSize(rozměr.width, rozměr.height);
    }


    /***************************************************************************
     * Nastaví nové rozměry instance.
     *
     * @param width    Nově nastavovaná width; width>0
     * @param height    Nově nastavovaná height; height>0
     */
    @Override
    public void setSize(int šířka, int výška)
    {
        if ((šířka == máŠířka)  &&  (výška == máVýška)) {
            aft = null;
        } else {
            aft = new AffineTransform();
            aft.translate(getX(), getY());
            aft.scale((double)šířka / máŠířka,  (double)výška / máVýška);
        }
        this.šířka = šířka;
        this.výška = výška;
        CM.redraw();
    }


    /***************************************************************************
     * Vrátí instanci třídy Area s informacemi o pozici a rozměrech instance.
     *
     * @return   Area s informacemi o pozici a rozměre instance.
     */
    public Area getArea()
    {
        return new Area(getX(), getY(), getWidth(), getHeight());
    }


    /***************************************************************************
     * Nastaví novou polohu a rozměry instance.
     *
     * @param oblast Nově nastavovaná oblast zaujímaná instancí.
     */
    public void setArea(Area oblast)
    {
        setArea(oblast.x, oblast.y, oblast.width, oblast.height);
    }


    /***************************************************************************
     * Nastaví pozici a rozměr objektu.
     *
     * @param pozice  Position objektu
     * @param rozměr   Size objektu
     */
    public void setArea(Position pozice, Size rozměr)
    {
        setArea(pozice.x, pozice.y, rozměr.width, rozměr.height);
    }


    /***************************************************************************
     * Nastaví novou pozici a rozměr objektu.
     *
     * @param x       x-ová souřadnice počátku, x>=0, x=0 má levý okraj plátna
     * @param y       y-ová souřadnice počátku, y>=0, y=0 má horní okraj plátna
     * @param width   Šířka vytvářeného objektu v bodech
     * @param height   Výška vytvářeného objektu v bodech
     */
    public void setArea(int x, int y, int šířka, int výška)
    {
        CM.dontDraw(); {
            setPosition(x,     y   );
            setSize(šířka, výška);
        } CM.returnDraw();
    }


    /***************************************************************************
     * Vrátí .
     *
     * @return
     */
    public Image getImage()
    {
        return image;
    }



//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Převede instanci na řetězec.
     *
     * @return Řetězcová reprezentace dané instance.
     */
    @Override
    public String toString()
    {
        return this.getClass().getSimpleName() + "#" + (100 + hashCode() % 900);
    }


    /***************************************************************************
     * {@inheritDoc}
     * @param painter
     */
    @Override
    public void paint(Painter painter)
    {
        painter.drawPicture(getX(), getY(), this, aft);
    }

//
//    /***************************************************************************
//     * Přijme návštěvníka a nechá jej provést jeho metodu.
//     *
//     * @param návštěvník  Přijímaný návštěvník
//     * @param param       Parametry návštěvníkovy metody
//     * @return Hodnota vrácená metodou návštěvníka
//     */
//    @Override
//    public Object přijmi(INávštěvník návštěvník, Object param)
//    {
//        return návštěvník.aplikujNa(this, param);
//    }
//


//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED TYPES AND INNER CLASSES ==========================================
//== TESTING CLASSES AND METHODS ===============================================

//    /***************************************************************************
//     * Test method.
//     * @return obr
//     * /
//     public static Picture test()
//     {
//         //Součet řetězců v následujících příkazech má jediný účel:
//         //aby tyto příkazy předčasně neukončovaly blokové zakomentování
////         Picture o = new Picture(0, 0, "*"+"/POKUS");
//         Picture o = new Picture(0, 0, "**"+"/XXX.PNG");
////         System.out.println("Obr.: " + o);
//         AktivníPlátno CM = AktivníPlátno.getPlátno();
//         CM.add(o);
////         System.out.println("KONEC");
//         return o;
//     }/**/
//     /** @param ppr Parametry příkazového řádku - nepoužité */
//     public static void main(String[]ppr){ TestObrázek.main(null); }//test(); }/*-*/
}
